Voxel Mosaics 1¶
Choose axial (A), coronal (C) or sagittal (S) slices. Modify with cross slices (X), renderings (R), and horizontal overlap (H).
See https://niivue.com/demos/features/mosaics.html for mirror.
In [1]:
from pathlib import Path
from ipyniivue import download_dataset
BASE_API_URL = "https://niivue.com/demos/images/"
DATA_FOLDER = Path("images")
# Download data for example
download_dataset(
BASE_API_URL,
DATA_FOLDER,
files=[
"mni152.nii.gz",
"spmMotor.nii.gz",
],
)
mni152.nii.gz already exists. spmMotor.nii.gz already exists. Dataset downloaded successfully to images.
In [2]:
import ipywidgets as widgets
from IPython.display import display
from ipyniivue import NiiVue
## Create NiiVue Instance and Load Data
nv = NiiVue(
is_colorbar=True,
is_alpha_clip_dark=True,
center_mosaic=True,
back_color=(1, 1, 1, 1),
)
nv.load_volumes(
[
{
"path": DATA_FOLDER / "mni152.nii.gz",
"colorbar_visible": False,
},
{
"path": DATA_FOLDER / "spmMotor.nii.gz",
"cal_min": 4.2,
"cal_max": 8,
"colormap": "warm",
"colormap_negative": "winter",
},
]
)
initial_mosaic = "A -20 50 60 70 C -10 -20 -50 S R X 0 R X -0"
nv.set_slice_mosaic_string(initial_mosaic)
@nv.on_canvas_attached
def setup_illumination():
"""Set volume render illumination after canvas attached."""
nv.set_volume_render_illumination(0.3)
## Create Interactive Controls
# mosaic string input
mosaic_text = widgets.Text(
value=initial_mosaic,
placeholder="Enter mosaic string",
description="Mosaic String:",
style={"description_width": "initial"},
layout=widgets.Layout(width="600px"),
)
# help button
help_button = widgets.Button(
description="Help",
button_style="info",
tooltip="Click for information about mosaic strings",
layout=widgets.Layout(width="80px"),
)
# outline slider
outline_slider = widgets.IntSlider(
min=0,
max=8,
value=0,
description="Outline:",
continuous_update=True,
)
# alpha mode dropdown
alpha_dropdown = widgets.Dropdown(
options=[
("Restrict colorbar to range", 0),
("Colorbar from 0, transparent subthreshold", 1),
("Colorbar from 0, translucent subthreshold", 2),
],
value=0,
description="Alpha Mode:",
style={"description_width": "initial"},
layout=widgets.Layout(width="400px"),
)
# glossy rendering dropdown
glossy_dropdown = widgets.Dropdown(
options=[
("Slices", -1),
("Matte", 0),
("Low", 0.3),
("Medium", 0.6),
("High", 1.0),
],
value=0.3,
description="Glossy:",
style={"description_width": "initial"},
)
# dark mode checkbox
dark_checkbox = widgets.Checkbox(
value=False,
description="Dark Mode",
)
# save button
save_button = widgets.Button(
description="Save Bitmap",
button_style="success",
tooltip="Save current view as PNG",
)
# output for messages
output = widgets.Output()
## Setup Event Handlers
def on_mosaic_change(change):
"""Handle mosaic string changes."""
nv.set_slice_mosaic_string(change["new"])
def on_help_click(b):
"""Display help information."""
with output:
output.clear_output()
print("Mosaic String Help:")
print("===================")
print("Choose axial (A), coronal (C) or sagittal (S) slices.")
print("Modify with:")
print(" - X: cross slices")
print(" - R: renderings")
print(" - H: horizontal overlap (e.g., H 0.3)")
print("")
print("Example: 'A -20 50 60 70 C -10 -20 -50 S R X 0 R X -0'")
print("This creates axial slices at positions -20, 50, 60, 70,")
print("coronal slices at -10, -20, -50, a sagittal slice,")
print("and renderings with cross sections.")
def on_outline_change(change):
"""Handle outline width changes."""
nv.overlay_outline_width = 0.25 * change["new"]
def on_alpha_change(change):
"""Handle alpha mode changes."""
nv.volumes[1].colormap_type = change["new"]
def on_glossy_change(change):
"""Handle glossy rendering changes."""
value = float(change["new"])
nv.set_volume_render_illumination(value)
def on_dark_change(change):
"""Handle dark mode toggle."""
if change["new"]:
nv.opts.back_color = (0, 0, 0, 1)
else:
nv.opts.back_color = (1, 1, 1, 1)
def on_save_click(b):
"""Save the current scene."""
with output:
output.clear_output()
nv.save_scene("mosaic_screenshot.png")
print("Scene saved as 'mosaic_screenshot.png'")
# attach event handlers
mosaic_text.observe(on_mosaic_change, names="value")
help_button.on_click(on_help_click)
outline_slider.observe(on_outline_change, names="value")
alpha_dropdown.observe(on_alpha_change, names="value")
glossy_dropdown.observe(on_glossy_change, names="value")
dark_checkbox.observe(on_dark_change, names="value")
save_button.on_click(on_save_click)
# initialize values
on_outline_change({"new": outline_slider.value})
on_alpha_change({"new": alpha_dropdown.value})
## Display All
# organize controls
mosaic_row = widgets.HBox([mosaic_text, help_button])
controls_row1 = widgets.HBox([outline_slider, alpha_dropdown])
controls_row2 = widgets.HBox([glossy_dropdown, dark_checkbox, save_button])
# create main layout
controls = widgets.VBox([mosaic_row, controls_row1, controls_row2, output])
# display everything
display(widgets.VBox([controls, nv]))